<?php

	/**
	 * <version greek="beta" major="1" minor="0">Cochin Splash Hen</version>
	 * <author email="njones@art-k-tec.com">Nika Jones</author>
	 * <copyright start="2007">Art-k-tec Systems, LLC</copyright>
	 * <license type="Apache2.0" href="http://www.opensource.org/licenses/apache2.0.php">Apache License, Version 2.0</license>
	 */
	
	abstract class bCache {
		const NULL				="\x4\x3\x7";
		const RETURN_BUFFER 	='[return][buffer][result]';
		const RETURN_PASSED		='[return][passed][result]';
		const RETURN_FUNCTION 	='[return][function][result]';
		
		private static $nMajor =1;
		private static $nMinor =0;
		private static $sRevision ="0000";
		
		protected $sType;
		protected $mCache;
		protected $aConfiguration;
		
		public static function version() { return self::$nMajor.'.'.self::$nMinor.'.'.self::$sRevision; }
		
		///<summary>
		///  Sets the configuration options of the cache
		///</summary>
		///<param type="array" name="aOption">The array of the key-value to configure</param>
		///<returns type="bCache">The cache object</returns>
		public function Configure(array $aOption) {
			
			foreach($aOption as $sKey =>$sValue) {
				
				$this->$aConfiguration[$sKey] =$sValue;
			}
			
			return $this;
		}
		
		///<summary>
		///  Starts the cache process
		///</summary>
		///<returns type="bool">Whether or not to use the cache or build the cache</returns>
		public function Open() {
			
			$aArgument =func_get_args();
			$bResult =(bool)call_user_func_array(array($this, $this->sType.'_open'), $aArgument);
	
			if($bResult) { ob_start(); }
			return $bResult;
		}
		
		///<summary>
		///  Ends the cache and returns what was either outputed, or passed in or runs another function
		///</summary>
		///<returns type="bCache" />
		public function Close($mCache =bCache::NULL) {
			
			$aArgument =func_get_args();
			$mBufferData =ob_get_contents(); ob_end_clean();
			
			if(!isset($this->aConfiguration['return_type'])) {
				
				if(in_array(($this->sType.'_close'), get_class_methods(get_class($this)))) {
					
					$this->aConfiguration['return_type'] =bCache::RETURN_FUNCTION;
				} else {
					
					$this->aConfiguration['return_type'] =bCache::RETURN_PASSED;
				}
			}
			
			switch($this->aConfiguration['return_type']) {
				
				case bCache::RETURN_BUFFER:
					$this->mCache =$mBufferData;
				break;
				
				case bCache::RETURN_FUNCTION:
					if(in_array(($sTypeClose =$this->sType.'_close'), get_class_methods(get_class($this)))) {

						$this->mCache =call_user_func_array(array($this, $sTypeClose), $aArgument);
					} else {
						
						$this->mCache =null; // should throw exception.
					}
				break;
				
				case bCache::RETURN_PASSED:
					$this->mCache =$mCache;
				break;
			}
			
			return $this;
		}
		
		///<summary>
		///  The result of the cache
		///</summary>
		///<returns type="mixed">Returns what was just cached</returns>
		public function Result() {
			
			return $this->mCache;
		}
		
		///<summary>
		///  Sets the type of cache being used, which in turn kicks off 
		//   hooks for pre and post cache functions
		///</summary>
		///<returns type="bCache" />
		public function Type($sType) {
			
			$this->sType =$sType;
			return $this;
		}
		
		///<summary>
		///   Sets the results of the cache
		///</summary>
		///<returns type="bCache" />
		protected function SetResult($mData) {
			
			$this->mCache =$mData;
			return $this;
		}
		
		///<summary>
		///   One type of built-in cache types, it looks for changed files within
		///   a directory and then re caches based on the directory scan
		///</summary>
		///<returns type="string">The hash of the directory scan</returns>
		protected function FileTimeHash($sFilePattern) {
			
			$sTime ='';
			$aPattern =glob($sFilePattern, GLOB_BRACE);

			$aPattern =is_array($aPattern) ? $aPattern : array();

			foreach($aPattern as $sPath) {

				foreach (
					new RecursiveIteratorIterator(
						new RecursiveDirectoryIterator(
							$sPath, RecursiveDirectoryIterator::KEY_AS_PATHNAME
						), RecursiveIteratorIterator::CHILD_FIRST
					)
				as $sFile =>$oInfo) {
					
					$sTime .=(int)filemtime($sFile);
				}
			}
			
			return md5($sTime);
		}
	}

?>